home *** CD-ROM | disk | FTP | other *** search
/ Aminet 12 / Aminet 12 (1996)(GTI - Schatztruhe)[!][Jun 1996].iso / Aminet / dev / lang / HeliOS4.lha / helios_demo_disk4 / tutorials / HeliOSLanguageTutorial3.doc < prev    next >
Encoding:
Text File  |  1995-11-11  |  85.9 KB  |  2,564 lines

  1.  
  2. Topics covered in this tutorial:
  3.  
  4. * About this tutorial...
  5. * Running examples
  6. * Setting up your own Vocabulary Help
  7. * Setting up your own vocabulary
  8. * Using DOS/AREXX macros
  9. * Setting up HeliOS command macros
  10. * A useful command for use in macros: EDIT
  11. * Another useful command for use in macros: RUN
  12. * Using HeliOS_cmp
  13. * Getting user input
  14. * Setting up text and graphic output
  15. * A little more about HeliOS text streams
  16. * HeliOS Variables
  17. * HeliOS Constants
  18. * More about the concepts of "Run-time" and "Compile-time"
  19. * The Dictionary pointer
  20. * Using "CREATE"
  21. * Run-time initialisation of data structures within Dictionary memory
  22. * Easy ways of setting up text strings in HeliOS
  23. * The "Code Field Address", or "CFA"
  24. * Vectored Execution
  25. * Error handling routines
  26. * Using the Return stack
  27. * Using HeliOS includes
  28. * Calling Amiga libraries
  29. * Setting up loops in HeliOS
  30. * Counted Loops
  31. * Conditional Loops
  32. * Infinite Loops
  33.  
  34.  
  35. ----------------------
  36. About this tutorial...
  37. ----------------------
  38.  
  39. By now, if you have followed all the preceding tutorial material, you
  40. should be fairly confident about writing small-scale HeliOS programs.
  41.  
  42. Some people like to build upon their own ideas and go on from here to
  43. to construct their own programs, learning the language as they go.
  44.  
  45. Other people like to work by copying and modifying existing programs,
  46. which is a also good way of learning more advanced techniques.
  47.  
  48. As you will have seen, HeliOS provides the source code for several example
  49. programs, and it is a good idea to look at these to see how larger scale
  50. HeliOS programs can be constructed.  Of course you may prefer to adopt a
  51. very different programming style: HeliOS is very flexible, and there are no
  52. fixed rules when it comes to program design.
  53.  
  54. If you want to follow on from the example programs provided with HeliOS
  55. there is full source code available for complete large programs such as the
  56. HeliOS "Defender" arcade game.
  57.  
  58. Whichever method of progress you choose, we cannot go too far along the
  59. learning path with you, for the simple reason that HeliOS is deliberately
  60. very flexible, and Amiga programming has so many facets that it would be
  61. quite impossible and undesirable to lay down fixed guidelines.
  62.  
  63. Nevertheless, there are a few important techniques, ideas, and points of
  64. interest which we can describe here, which will perhaps help to speed up
  65. your progress in the early stages.  This tutorial is devoted to a brief
  66. discussion of various topics which you will hopefully find interesting,
  67. and which you can build upon in your own work by reading the more detailed
  68. documentation in the "Dictionary.doc" and elsewhere.
  69.  
  70. The sections of this tutorial have no particular natural order, and are
  71. presented as a mixed bag of stimulating ideas: if you yourself have further
  72. ideas which you think would benefit other HeliOS programmers, please let us
  73. know so that we can include them in future versions of the tutorials.
  74.  
  75. Remember that the techniques and ideas mentioned here are only a selected
  76. few of the ways you can use HeliOS.  It is a good idea to read the HeliOS
  77. "Dictionary.doc" file very carefully, since it describes many functions and
  78. methods which you will find useful in particular circumstances.
  79.  
  80.  
  81. ----------------
  82. Running examples
  83. ----------------
  84.  
  85. This tutorial contains many shorts sections of example code.
  86.  
  87. Remember that you can easily run these examples from the editor by simply
  88. highlighting them and pressing <Amiga-e>.
  89.  
  90. Note that many short example phrases have associated comments to the right
  91. of them, often using a preceding "->" symbol.
  92.  
  93. These "->" symbols, and the following comments, are merely intended to
  94. indicate what the code fragment is doing, and should not be included in
  95. highlighted sections of code to be run-tested: if you do try to run these
  96. comments, you will merely get an error.
  97.  
  98.  
  99. -----------------------------------
  100. Setting up your own Vocabulary Help
  101. -----------------------------------
  102.  
  103. The Vocabulary Help system is intended to be easy for you to use yourself
  104. to create your own notes on any HeliOS function.
  105.  
  106. Place the cursor over the word "OpenScreen" below and press <Ctrl-Help> to
  107. see the brief Vocabualry Help available on that HeliOS command word.
  108.  
  109. OpenScreen
  110.  
  111. Notice that only a stack diagram is given, with no descriptive notes: this
  112. is because the Vocabulary Help system is intended to give very short quick
  113. help to which you can easily add your own notes as required by editing the
  114. Vocabulary Help file in one of the HeliOS editors.
  115.  
  116. Each individual has their own needs when it comes to help and reminders on
  117. various functions.  It is really easy to add your own help notes, so do not
  118. hesitate to start making your own additions to the help file.
  119.  
  120. As you will have seen, the Vocabulary Help file provided as a starting point
  121. merely displays a stack diagram, and this leaves plenty of spare space for
  122. any text comments you wish to add.  The Vocabulary Help file itself contains
  123. instructions on how to add your own help text: just load this file into one
  124. of the HeliOS editors and read the instructions given in the file.
  125.  
  126. The Vocabulary Help system is intended for brief quick "memory jogging"
  127. help, rather than detailed texts, and allows two short "pages" of help text
  128. which are quick to read and access: do not write an "essay" for Vocabulary
  129. Help, but give information which can be taken in at a glance.
  130.  
  131. We recommend that you become familiar with this system early in your HeliOS
  132. programming so that you get maximum benefit during the learning period when
  133. help is most required.  You will also find that the very act of creating
  134. your own help texts will in itself help you learn much relevant information.
  135.  
  136.  
  137. ------------------------------
  138. Setting up your own vocabulary
  139. ------------------------------
  140.  
  141. You will probably soon find that you have created a nucleus of useful
  142. HeliOS functions which you like to use in all your programs, and you may
  143. even create separate "toolkits" of functions for different applications.
  144.  
  145. You COULD manually load your special vocabulary each time you start HeliOS,
  146. or you COULD cut and paste this vocabulary into each of your program source
  147. code files, but this is rather tedious.
  148.  
  149. It is easy, in fact, to include any special vocabularies by simply using
  150. "RUN" to load the relevant source code file at the start of your program.
  151.  
  152. You can RUN as many separate external source code files as you wish from
  153. within any source code file, and you can also RUN source code files which
  154. themselves RUN other files: the system is very flexible and easy to use.
  155.  
  156. Here is an example showing how to use RUN to compile an external source code
  157. file from within any program:
  158.  
  159. RUN HeliOS:Source/MyOwnVocabulary.src
  160.  
  161.  
  162. The above line could be included anywhere in your source code, but would
  163. usually be placed immediately after the
  164.  
  165. FORGET **CORE**
  166.  
  167. line with which most programs begin.
  168.  
  169.  
  170. In fact the start of your source code is probably where you would want to
  171. initialise all of the general environment for your program, so you might
  172. have a typical program start something like this:
  173.  
  174.  
  175. FORGET **CORE**
  176.  
  177. AMIGAINCLUDE HeliOS:HeliOS_AmigaInclude
  178. USERINCLUDE  HeliOS:HeliOS_UserInclude
  179.  
  180. DOSCMD $Assign MyProgram: HeliOS:MyProgram$
  181.  
  182. RUN HeliOS:Source/MyOwnVocabulary.src
  183. RUN MyProgram:MyProgramToolkit.src
  184.  
  185. etc. etc.
  186.  
  187.  
  188. ----------------------
  189. Using DOS/AREXX macros
  190. ----------------------
  191.  
  192. You will have noticed that the HeliOS editors have a macro recording system
  193. which allows you to record DOS/AREXX macro command lines and execute them
  194. via hot-keys for easy and instantaneous operation.
  195.  
  196. These macros can only be created in the editor environment, but you should
  197. be aware that they can be executed both in the editor AND the interpreter
  198. environments.
  199.  
  200. This useful facility allows you to make use of instant hot-key DOS or AREXX
  201. commands in the interpreter as well as the editors.
  202.  
  203. Note that ordinary editor macros cannot be run from the interpreter: only
  204. DOS/AREXX macros have this facility.
  205.  
  206. See the "DOSandAREXX_Commands.doc" for more details
  207.  
  208.  
  209. --------------------------------
  210. Setting up HeliOS command macros
  211. --------------------------------
  212.  
  213. You can attach a HeliOS command line to a hot-key, and this allows you to
  214. run any HeliOS program at the touch of a key.
  215.  
  216. This can be useful if you wish to use a certain command sequence often: for
  217. example you may like to attach the "FORGET **CORE**" command to a hot-key.
  218.  
  219. To do this you must create a special form of DOS/AREXX macro.
  220.  
  221. If you want to set up a DOS/AREXX macro command line to be treated as a
  222. HeliOS command line you must place a special code at the start of the line.
  223.  
  224. There are two possible codes, "H>" and "E>", which HeliOS interprets in
  225. slightly different ways.
  226.  
  227. 1. Using H>
  228.  
  229.   Placing H> at the start of the DOS/AREXX command line will cause HeliOS to
  230.   execute that line as HeliOS code in a full interpreter "session", just as
  231.   if that line had been entered at the interpreter command line.
  232.  
  233.   For example, setting up this line as a macro:
  234.  
  235.   H> FORGET **CORE**
  236.  
  237.   will produce a macro command which behaves exactly as if you had typed
  238.   "FORGET **CORE**" at the intepreter command line.
  239.  
  240. 2. Using E>
  241.  
  242.   Placing E> at the start of the DOS/AREXX command line will cause HeliOS to
  243.   execute that line as HeliOS code without registering a full interpreter
  244.   "session".
  245.  
  246.   The code will simply be executed without all the extra business of the
  247.   session log etc.
  248.  
  249.   For example, setting up this line as a macro:
  250.  
  251.   E> FORGET **CORE**
  252.  
  253.   will produce a macro command which executes apparently in the background,
  254.   with no visible effect but still doing its job of clearing the dictionary.
  255.  
  256. See the "HeliOS_Macro_Commands.doc" for more details.
  257.  
  258.  
  259. ----------------------------------------
  260. A useful command for use in macros: EDIT
  261. ----------------------------------------
  262.  
  263. You might like to set up macros, as explained above, to edit certain files
  264. which you use very often.  To do this you can use the very useful EDIT
  265. command, which allows you to auto-load any file into a HeliOS editor.
  266.  
  267. Look at this macro command line, for example:
  268.  
  269. E> 3 EDIT S:Startup-sequence
  270.  
  271. This will load the "Startup-sequence" file into HeliOS Editor3.
  272.  
  273. Here is how the command works:
  274.  
  275. E> 3 EDIT S:Startup-sequence
  276.    ^ ^^^^ ^^^^^^^^^^^^^^^^^^
  277.    | |    |
  278.    | |    File name
  279.    | |
  280.    | Edit command
  281.    |
  282.    Which editor you want the file to be loaded into
  283.  
  284. If there is already unsaved text in the specified editor you will get a
  285. warning, giving you the opportunity to save the old text first.
  286.  
  287.  
  288. ---------------------------------------------
  289. Another useful command for use in macros: RUN
  290. ---------------------------------------------
  291.  
  292. You might like to set up macros, as explained above, to run certain HeliOS
  293. programs, and to do this you can use the very useful RUN command.
  294.  
  295. For example:
  296.  
  297. F> RUN HeliOS:Source/MyUsefulProgram
  298.  
  299. Using this method you could, for example, attach particular sets of your 
  300. own "Toolkit" commands to each Function key, and thus you could customise 
  301. your HeliOS environmemt at the touch of a key.
  302.  
  303. The fact that you can attach literally ANY HeliOS program to a command key
  304. gives you limitless scope to customise your own programming environment.
  305.  
  306.  
  307. ----------------
  308. Using HeliOS_cmp
  309. ----------------
  310.  
  311. The HeliOS_cmp program can be used as a straightforward stand-alone HeliOS
  312. compiler, or as a versatile method of testing any HeliOS program.
  313.  
  314. The latter option is very useful provided that you observe the constraint
  315. that the full interpreter environment will not be available, so you cannot
  316. run software which uses facilities only present in the full interactive
  317. HeliOS system.
  318.  
  319. Remember also that source code run from HeliOS_cmp will need to contain
  320. explicit commands to load whatever include files are required, whereas in
  321. the full interactive system include files are usually permanently on-line.
  322.  
  323. HeliOS_cmp can be used in various different ways, and it is worth looking
  324. at these in this tutorial:
  325.  
  326. 1. As a compiler of stand alone programs for use with HeliOS_exe.
  327.  
  328.    In this case you are interested in generating a compiled code file, but
  329.    not a compiled vocabulary module as used in the full interpreter.
  330.  
  331.    You would use the "-v" command line option to prevent generation of a
  332.    full vocabulary module.
  333.  
  334.    You would use a command line using "-v" something like this:
  335.  
  336.    HeliOS:HeliOS_cmp HeliOS:Source/MyProgram Ram:MyProgram -v
  337.    ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^
  338.    |                 |                       |             |
  339.    Compiler program  Source code file        Target file   Specifies no
  340.                                              (Optional)    vocabulary module
  341.  
  342.    Note that if you do not specify a target file the compiled file will be
  343.    given the same name and path as the source file with a ".cmp" suffix.
  344.  
  345.    The HeliOS_cmp program will open a 4-colour screen and present you with
  346.    full compilation text output and error messages.
  347.  
  348.    In this case a final end-of-compilation message and free bytes statement
  349.    will apppear.
  350.  
  351.  
  352. 2. As a compiler of programs to be "preloaded" into the interpreter.
  353.  
  354.    In this case you need to generate a compiled code file and a compiled
  355.    vocabulary module to be used by the full interpreter.
  356.  
  357.    You would NOT use the "-v" command line option, but otherwise the command
  358.    line format would be just like the previous case.
  359.  
  360.    HeliOS:HeliOS_cmp HeliOS:Source/MyProgram Ram:MyProgram
  361.    ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
  362.    |                 |                       |
  363.    Compiler program  Source code file        Target file
  364.                                              (Optional)
  365.  
  366.    Note that if you do not specify a target file the compiled file will be
  367.    given the same name and path as the source file with a ".cmp" suffix.
  368.  
  369.    The vocabulary module will have the same name but with a "V" suffix.
  370.  
  371.    The HeliOS_cmp program will open a 4-colour screen and present you with
  372.    full compilation text output and error messages.
  373.  
  374.    In this case a final end-of-compilation message and free bytes statement
  375.    will apppear.
  376.  
  377.  
  378. 3. To test run programs without generating any output files
  379.  
  380.    In this case want to simply compile a program and you are only interested
  381.    in seeing the program run, not in generating compiled code.
  382.  
  383.    To do this you specify the command line option "null", as follows:
  384.  
  385.    (Note that the "null" can be in upper case (e.g. "NULL") if you wish)
  386.  
  387.    HeliOS:HeliOS_cmp HeliOS:Source/MyProgram null
  388.    ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
  389.    |                 |                       |
  390.    Compiler program  Source code file        Specify NO output files
  391.  
  392.    In this case you will probably want a visual environment for your program
  393.    as close as possible to the setup of the full HeliOS interpreter.
  394.  
  395.    The HeliOS_cmp program will try to simulate the interactive HeliOS system
  396.    display by by opening an 8-colour screen and setting its colours to your
  397.    existing saved HeliOS system default colours.
  398.  
  399.    With this option the final end-of-compilation message and the free bytes
  400.    statement will not apppear.
  401.  
  402.  
  403. ------------------
  404. Getting user input
  405. ------------------
  406.  
  407.    The Amiga allows many methods of gathering user input, and most of them
  408.    are rather complex to set up and administer.
  409.  
  410.    Probably the most common, flexible, and system friendly method is to use
  411.    an Intuition IDCMP (Intuition Direct Communication Message Port) which
  412.    will gather user input from an active Intuition window.
  413.  
  414.    This can still be a very tedious process, but you are quite at liberty
  415.    to use this method within HeliOS if you wish.
  416.  
  417.    However, the good news is that HeliOS provides a sophisticated automatic
  418.    IDCMP handler which is ridiculously easy to set up and use.
  419.  
  420.    You can read more about this in the dictionary documentation, but here
  421.    we will give a simple description of how to set up the HeliOS IDCMP
  422.    handler.
  423.  
  424.    First of all, you must understand that the HeliOS IDCMP handler can only
  425.    be used in conjunction with an Intuition window, which is fairly obvious
  426.    since it employs an Intuition IDCMP!
  427.  
  428.    Next you must remember that there can be only one HeliOS IDCMP handler
  429.    in operation at any particular time.
  430.  
  431.    When HeliOS starts up it always opens an IDCMP handler and attaches this
  432.    to the HeliOS startup window: you do not have to do anything at all to
  433.    set up this initial facility.
  434.  
  435.    Subsequently you can reset the HeliOS IDCMP handler to get user input
  436.    from any window which your program opens, and you can switch easily and
  437.    quickly between as many different windows as you wish.
  438.  
  439.    Finally, when you have finished, you should return the IDCMP handler to
  440.    the HeliOS window.
  441.  
  442.    You do not need to worry about finally closing the HeliOS IDCMP handler,
  443.    because it will be closed automatically when HeliOS itself closes down.
  444.  
  445.    To set the HeliOS IDCMP handler to get input from a new window you have
  446.    just opened, you would say something like:
  447.  
  448.    MyNewWindow D@ MAKEINWINDOW
  449.  
  450.    The simple MAKEINWINDOW command is all that is required to set up user
  451.    input from any window.
  452.  
  453.    To restore user input to the main HeliOS window you should use the single
  454.    word:
  455.  
  456.    FORTHINWINDOW
  457.  
  458.    Remember that you MUST transfer the HeliOS IDCMP handler back to the
  459.    HeliOS window before closing the other window you have been using.
  460.  
  461.    It really is that simple to set up the HeliOS user input handler!
  462.  
  463.    Of course, having attached the HeliOS user input handler to a window, you
  464.    still need to know how to check for user input.
  465.  
  466.    This is very easy indeed, and is most often done using the word "KEY",
  467.    which will halt program execution and wait for ANY user input.  As soon
  468.    as KEY finds some user input to report it "wakes up" and returns a code
  469.    on the stack defining just what happened.  If it was a simple key press
  470.    you will receive an ASCII code, if it was another input event such as a
  471.    gadget you will get a special code informing you just what happened.
  472.  
  473.    If you need further information about the nature of the event, you can
  474.    get more details by inspecting special system variables such as RAWKEY,
  475.    QUALIFIER, GADGETNUMBER, MENUNUMBER etc..
  476.  
  477.    Of course, you may not want your program to go to sleep while waiting
  478.    for user input, and in this case you can use the word "?TERMINAL", which
  479.    tests for user input and returns at once with a user input code on the
  480.    stack, or "null" if nothing is happening.
  481.  
  482.    It is important to become familiar with the use of MAKEINWINDOW, KEY,
  483.    and ?TERMINAL right from the start of your HeliOS programming.
  484.  
  485.    This system is so easy to use that you will very soon become fluent in
  486.    writing code using the simple input words described: there are more
  487.    sophisticated tools available within HeliOS, but you will not need these
  488.    to start with.
  489.  
  490.    Here is a short example which shows the use of KEY.
  491.  
  492.    : TESTKEY
  493.  
  494.    SCRCLR
  495.  
  496.    5 4 CURPUT ." Press any key to see ASCII code returned by KEY ->"
  497.    5 6 CURPUT ." Press <Space> to quit"
  498.  
  499.    BEGIN
  500.      KEY           \ Get KEY
  501.      56 4 CURPUT   \ Set cursor position
  502.      6 FPENSET     \ Set colour to red
  503.      DUP .         \ Duplicate and print ASCII code
  504.      32 =          \ Check if it was <Space>
  505.    UNTIL
  506.    SCRCLR
  507.    ;
  508.  
  509.    TESTKEY
  510.  
  511.    See the "Dictionary.doc" and example programs for more details.
  512.  
  513.  
  514. ----------------------------------
  515. Setting up text and graphic output
  516. ----------------------------------
  517.  
  518.    In the previous section you saw how easy it was to set up user input
  519.    within any window using MAKINWINDOW.
  520.  
  521.    The good news is that equally simple and rather similar methods are
  522.    available for setting up text and graphic output in windows.
  523.  
  524.    To set up text output you use the function "MAKEOUTWINDOW", and to set
  525.    up graphical output you use "MAKEGFXWINDOW".
  526.  
  527.    So, if you wanted to make a newly opened window active for user input,
  528.    text output, and graphics output, you might say:
  529.  
  530.    MyNewWindow D@ MAKEGFXWINDOW
  531.    MyNewWindow D@ MAKEOUTWINDOW
  532.    MyNewWindow D@ MAKEINWINDOW
  533.  
  534.    Remember again that you MUST transfer the all HeliOS functions back to
  535.    the HeliOS window before closing the other window you have been using.
  536.  
  537.    You saw in the previous section how to close user input by returning the
  538.    HeliOS IDCMP handler to the HeliOS window, using "FORTHINWINDOW".
  539.  
  540.    The method of closing down text output is like that used to close the
  541.    HeliOS IDCMP handler, except that you use the function "FORTHOUTWINDOW".
  542.  
  543.    The method of closing down graphic output is slightly different, and in
  544.    this case you need to use two words:
  545.  
  546.    FWINDOW MAKEGFXWINDOW
  547.  
  548.    Once you have set up text and graphic output in your window you can use
  549.    a whole range of convenient pre-coded HeliOS functions: HeliOS has many
  550.    powerful text functions associated with its system of ten text streams
  551.    and a complete set of graphic rendering functions.
  552.  
  553.    See the "Dictionary.doc" for more details.
  554.  
  555.  
  556. ---------------------------------------
  557. A little more about HeliOS text streams
  558. ---------------------------------------
  559.  
  560.    HeliOS text output, as you have seen in the earlier tutorials, is sent
  561.    through a series of text streams which can be used to remember many
  562.    characteristics of a text window.
  563.  
  564.    It is worth looking at the "Dictionary.doc" to see the wide range of text
  565.    control functions available in HeliOS, but there are so many of these
  566.    that you will probably find it easiest to learn them slowly as you need
  567.    them.
  568.  
  569.    However, the use of the words STREAM and STREAMNO is worth describing at
  570.    this point, because they are fundamental to using text streams.
  571.  
  572.    The word STREAMNO returns the number of the current text stream, and is
  573.    very useful when you need to remember the old stream while jumping on
  574.    a temporary basis to another stream.
  575.  
  576.    You can use code something like this:
  577.  
  578.  
  579.    SCRCLR
  580.  
  581.    ." Here we are, starting off!"
  582.  
  583.    STREAMNO                      \ Get current stream number onto stack
  584.  
  585.    8 STREAM                      \ Jump to new stream - number 8
  586.  
  587.    10 10 60 12 SCRWIN
  588.    7 BPENSET 6 FPENSET
  589.    SCRCLR
  590.    ." Here we are in Stream 8!"
  591.    CR
  592.    CR
  593.    ." We were in Stream " DUP .  \ Duplicate original stream number in stack
  594.    CR
  595.    CR
  596.    ." And now we are going back!"
  597.  
  598.    STREAM                        \ Jump back to original stream
  599.  
  600.    1 20 CURPUT
  601.  
  602.    ." Now we are back!"
  603.    CR
  604.    CR
  605.    ." Press <Space> to continue."
  606.  
  607.    WAITSPACE
  608.  
  609.    SCRCLR
  610.  
  611.  
  612.    Try running this section of code.
  613.  
  614.  
  615.    The word STREAM must be preceded by a stream number which must lie in
  616.    the range 0-9 to select one of the ten HeliOS text streams (note that
  617.    if you specify a number greater than "9" HeliOS will use a value of "9"
  618.    internally by default).
  619.  
  620.    Note, by the way, that the text stream system is unique to HeliOS and is
  621.    NOT part of the Amiga operating system: it USES the Amiga console device
  622.    but it is not part of the standard Amiga console device functionality.
  623.  
  624.    Once you have defined the current text stream, HeliOS will allow you to
  625.    set up a text window (using the SCRWIN function) and define text styles,
  626.    cursor position etc..
  627.  
  628.    Then you can change streams and set up another text window with different
  629.    styles etc.
  630.  
  631.    Subsequently, simply evoking one of your preset streams will restore all
  632.    text parameters to the ones defined for that stream.
  633.  
  634.    Note that text stream windows are NOT the same as Intuition windows, and
  635.    you can have ten different text stream windows within a single Intuition
  636.    window.
  637.  
  638.    When organising text within a window it is often desirable to have some
  639.    lines of text at odd pixel offsets from other text: in other words, to
  640.    have text lines not dictated in terms of font dimension displacement.
  641.  
  642.    This is easy to set up with HeliOS streams, and you can easily have two
  643.    adjacent text streams with a single pixel difference in either vertical
  644.    or horizontal alignment if you wish.
  645.  
  646.    To change pixel alignment of a text window you use the "SETCONORIGIN"
  647.    command, immediately before performing a SCRWIN operation.  The SCRWIN
  648.    function will then configure its window with respect to the new pixel
  649.    origin.
  650.  
  651.    You should always use the FCONORIGIN function to reset the standard text
  652.    origin after creating a special offset text window, and it is a good idea
  653.    to do this immediately after the SCRWIN call.
  654.  
  655.    Remember in this context that the SETCONORIGIN command only affects the
  656.    SCRWIN command, and after using SCRWIN you can freely use SETCONORIGIN
  657.    without having any effect on text output until the next SCRWIN command.
  658.  
  659.    Notice also that the word STREAM itself uses SCRWIN to initiate the text
  660.    window of a newly selected stream, so you must be careful not to leave
  661.    the text origin set to some peculiar setting.
  662.  
  663.    * It is important to note that streams do NOT remember individual pixel
  664.      origin settings.
  665.  
  666.    So, the best philosophy for using SETCONORIGIN is to use this function
  667.    immediately before SCRWIN and then use FCONORIGIN immediately afterwards
  668.    to revert to the standard origin settings.
  669.  
  670.    For example:
  671.  
  672.    1 5 8 8 SETCONORIGIN
  673.    10 10 40 5 SCRWIN
  674.    FCONORIGIN
  675.    etc.
  676.    etc.
  677.  
  678.    Note that the parameters to the SETCONORIGIN function have two distinct
  679.    categories:
  680.  
  681.    1. The origin pixel offsets (horizontal and vertical)
  682.    2. The font-related character multipliers (horizontal and vertical)
  683.  
  684.    The origin pixel offsets are simple additive offsets, specified as either
  685.    positive or negative, and are used to fine-tune the final screen position
  686.    of the text window.
  687.  
  688.    The character multipliers are pixel values by which the window top left
  689.    corner character offsets specified in SCRWIN are multiplied to give the
  690.    initial pixel position for the top left corner of the text window.
  691.  
  692.    Character multipliers relate to horizontal and vertical font resolution,
  693.    and would normally each be set to 8 for a standard 8x8 pixel font.
  694.  
  695.    For example:
  696.  
  697.    0 5 8 8 SETCONORIGIN
  698.  
  699.    sets the vertical pixel offset to 5, and the vertical multiplier to 8.
  700.  
  701.    If you now say:
  702.  
  703.    20 12 40 8 SCRWIN
  704.  
  705.    you are asking for a text window which starts 12 text character rows
  706.    from the top of the console window.
  707.  
  708.    Since you have specified the font "character multiplier" as "8", the
  709.    first thing HeliOS will do to get the vertical window pixel displacement
  710.    is to multiply the character row offset by the character multiplier to
  711.    get an initial text window vertical pixel offset:
  712.  
  713.    12 x 8 = 96 pixels
  714.  
  715.    Having arrived at this basic font-related overall offset, HeliOS applies
  716.    the fine-tuning offset adjustment specified by the origin pixel offset.
  717.  
  718.    In our example this would mean adding 5 pixels to the vertical offset.
  719.  
  720.    96 + 5 = 101 pixels
  721.  
  722.    Thus our text window would open 101 pixels from the top of the console
  723.    window.
  724.  
  725.    Text window pixel origin offset settings can be determined and modified
  726.    individually using the variables CONHOFFSET and CONVOFFSET, and the
  727.    character multipliers can be determined and modified individually using
  728.    the variables CONHSCALE and CONVSCALE.
  729.  
  730.    Note that simply storing a value in one of these variables is sufficient
  731.    to set the origin for the next use of SCRWIN, and reading these variables
  732.    will always give you the current text window origin setting.
  733.  
  734.    See the "Dictionary.doc" for more details.
  735.  
  736.  
  737. ----------------
  738. HeliOS Variables
  739. ----------------
  740.  
  741. HeliOS, as you know, handles much of its parameter passing via the stack.
  742.  
  743. Other languages make more use of named variables, and many programmers
  744. who are already experienced with, for example, BASIC, may feel initially
  745. uncomfortable when confronted with the stack-oriented HeliOS system.
  746.  
  747. Actually you can, and indeed must, use named variables in HeliOS to an
  748. extensive degree, although in some cases this may be less efficient (and
  749. often more involved) than using the stack.
  750.  
  751. In most cases local parameter passing is best implemented using the stack,
  752. but global parameters are generally stored as variables.
  753.  
  754. In some languages variables are treated as more or less "abstract" entities
  755. with sometimes quite complex properties, restrictions, and error checking.
  756.  
  757. In HeliOS, variables are very transparently and directly associated with the
  758. accessing of data stored directly in memory: they are in no way complex or
  759. mysterious, and have very practical useage.  In HeliOS a variable is simply
  760. an allocated section of memory with which a name has been associated.
  761.  
  762. Although many other languages may obscure the fact, the use of variables is
  763. really all about naming a memory location where you are storing data, and
  764. this simple scenario is exactly how you should regard HeliOS variables.
  765.  
  766. After all, what the computer is really doing when you manipulate a variable
  767. is to move data in and out of a labelled storage location: even in languages
  768. which attempt to insulate (isolate) you from the reality of what the CPU is
  769. doing, the underlying action is fundamentally similar.  The problem is that
  770. the more you are insulated from direct considerations of the computer's CPU,
  771. the less efficient will be the data handling of your programs.
  772.  
  773. HeliOS variables can be in 3 data sizes (Byte, Word, and Long), and you can
  774. easily generate string variables which contain counted ASCII text strings.
  775.  
  776. Calling a HeliOS variable results in an address being placed on the stack:
  777. remember that this is NOT the variable data value (the variable contents),
  778. but the address where that variable's data is stored.
  779.  
  780. You can regard variables as a little like "mail boxes" in memory, and these
  781. "boxes" have very simple properties:
  782.  
  783. 1. Each variable has a unique identifying address which can be either 16-bit
  784.    or 32-bit, depending how you defined the variable.
  785.  
  786. 2. Each variable has a space allocated for storing its contents, and this
  787.    data space can be either 1 Byte (8-bits), 1 Word (16-bits), or 1 LongWord
  788.    (32-bits) in length for normal data variables.
  789.  
  790.    The "length" of string variables obviously depends on the length of the
  791.    string itself.
  792.  
  793. 3. Each variable has a name
  794.  
  795. HeliOS variables are really very simple indeed, and have absolutely no
  796. constraints or checks whatever on useage.
  797.  
  798. Variables are not "typed" in HeliOS, which is to say that the data stored
  799. in any numeric variable can be whatever you choose.
  800.  
  801. Furthermore, HeliOS does no checking whatever on what you are doing with
  802. the contents of a variable: if you are silly enough to use the contents of
  803. a pure data variable as an address by mistake, HeliOS will let you go ahead
  804. and do it!  It also is up to you to keep track of what size a variable is,
  805. and HeliOS will not check to see if you are trying to store a longword value
  806. into a byte sized variable.
  807.  
  808. In other words you have total freedom (and therefore speed and efficiency)
  809. in handling variables, but it is entirely your own responsibility to ensure
  810. that you get everything correct.  Most programmers would agree that this
  811. speed and freedom is ideal, but it may come as a shock to programmers who
  812. have been used to somewhat more restrictive systems.
  813.  
  814. In this respect, as in many others, HeliOS is more like assembly language
  815. than other high level languages.
  816.  
  817.  
  818. When a HeliOS data variable is defined, the following need to be specified:
  819.  
  820. 1. The initial data value
  821.  
  822. 2. The data size (Byte, Word, or Long)
  823.  
  824. 3. The addressing size (16-bit or 32-bit)
  825.  
  826. 4. The variable's name
  827.  
  828.  
  829. This process of variable definition is very easy indeed.
  830.  
  831. Here are a few examples, creating a variable called "PIGLETS":
  832.  
  833. 123  VARIABLE  PIGLETS  -> 16-bit data, initial value 123, 16-bit addressed
  834.  
  835. 123. DVARIABLE PIGLETS  -> 32-bit data, initial value 123, 16-bit addressed
  836.      ^
  837.      Specifies 32-bit data
  838.  
  839. 123  VARIABLEL PIGLETS  -> 16-bit data, initial value 123, 32-bit addressed
  840.              ^
  841.              Specifies 32-bit addressing
  842.  
  843. 123  CVARIABLE PIGLETS  -> 8-bit data, initial value 123, 16-bit addressed
  844.      ^
  845.      Specifies 8-bit data
  846.  
  847. 123. DVARIABLEL PIGLETS -> 32-bit data, initial value 123, 32-bit addressed
  848.  
  849.  
  850. After this initial specification, whenever you use the variable's name you
  851. will get on the stack the address (either 16-bit or 32-bit, depending on
  852. how the variable was defined) where the variable's contents are stored.
  853.  
  854. For example, let us assume that you want to create a normal 16-bit addressed
  855. variable called APPLES, with a value of "10" stored in it.
  856.  
  857. You could define such a variable like this:
  858.  
  859. 10 VARIABLE APPLES
  860.  
  861. Note that you always have to supply an initial value when you first create
  862. a HeliOS variable, and saying simply
  863.  
  864. VARIABLE APPLES
  865.  
  866. will result in an error.
  867.  
  868. If you now say, in your program code or the command line, the word APPLES,
  869. HeliOS will place on the stack the 16-bit variable address: this address
  870. is the place in memory where the number 10 is at present stored.
  871.  
  872. Having got the variable address on the stack, you can either change the
  873. value of the data stored there, or read the old data contents.
  874.  
  875. To change the contents of a variable, you might say
  876.  
  877.  15 APPLES !     -> Stores a new value of "15" into APPLES
  878.  
  879. To get the current contents of a variable, you might say
  880.  
  881.  APPLES @        -> Gets the current value of APPLES onto the stack
  882.  
  883. Incrementing and decrementing variables is very simple:
  884.  
  885.  APPLES INC      -> Increment the APPLES variable
  886.  
  887.  APPLES DEC      -> Decrement the APPLES variable
  888.  
  889. Moving data between variables is easy too:
  890.  
  891.  APPLES FRUIT MOVE -> Move the data contents of APPLES into FRUIT
  892.  
  893. There are various words for getting and storing values in variables, and
  894. in general these functions are exactly the same functions which you use in
  895. ordinary memory accessing operations.
  896.  
  897. In fact, always remember that a variable IS just a neatly labelled section
  898. of memory as far as HeliOS is concerned.
  899.  
  900. See the "Dictionary.doc" section on "MEMORY OPERATIONS" for a full list of
  901. all the many powerful ways of accessing variables and memory in HeliOS.
  902.  
  903.  
  904. ----------------
  905. HeliOS Constants
  906. ----------------
  907.  
  908. HeliOS Constants are even easier to use than variables, and are defined in
  909. a very similar way by specifying:
  910.  
  911. 1. The initial data value
  912.  
  913. 2. The data size (Word, or Long)
  914.  
  915. 3. The constant's name
  916.  
  917. Note that because HeliOS does not support byte sized stack or dictionary
  918. cells, it would be pointless to have a byte sized constant.
  919.  
  920. Such a constant would need to be stored in 2 bytes of memory space and
  921. would require a 2 byte stack cell, thus effectively being no different
  922. from a normal 16-bit constant.
  923.  
  924.  
  925. Here are examples of constant definitions:
  926.  
  927. 123  CONSTANT  PIGLETS  -> 16-bit data, initial value 123
  928.  
  929. 123. DCONSTANT PIGLETS  -> 32-bit data, initial value 123
  930.      ^
  931.      Specifies 32-bit data
  932.  
  933. Once defined, when the constant's name is used, the actual data value of
  934. the constant will be placed on the stack.
  935.  
  936.  
  937. --------------------------------------------------------
  938. More about the concepts of "Run-time" and "Compile-time"
  939. --------------------------------------------------------
  940.  
  941. HeliOS is both a compiler and an interpreter, and in many cases the same
  942. functional "words" are used by HeliOS in both modes of operation.
  943.  
  944. In fact "compilation" is actually performed by the "interpreter", so you
  945. could perhaps say that during compilation a dual process of compilation and
  946. interpretation is taking place.  This introduces a "dual-time" concept with
  947. respect to any program, because there will be some words specified within
  948. the program source code which are executed WHEN COMPILING, and others which
  949. only execute WHEN THE PROGRAM IS RUN later.
  950.  
  951. In general we use two terms to distinguish between the execution times of
  952. HeliOS functions:
  953.  
  954. 1. COMPILE-TIME
  955.  
  956.    When a word executes while HeliOS is compiling a program, this is said
  957.    to be "COMPILE-TIME" execution for that word.
  958.  
  959.    An example of this is the word ":" with which you begin word definitions
  960.    in your source code.  When HeliOS is compiling your program, it reads
  961.    the ":" and immediately (at COMPILE-TIME) executes that word in order to
  962.    initiate the colon definition.
  963.  
  964. 2. RUN-TIME
  965.  
  966.    Words specified within colon definitions are not executed as the program
  967.    is compiled, but only later when that defined word is run either in the
  968.    program itself or from the command line.
  969.  
  970.    As HeliOS at compile-time reads word names specified within a colon
  971.    definition, it will simply compile them.  The functions thus compiled
  972.    will not be executed until later at RUN-TIME when the program is actually
  973.    running.
  974.  
  975. When command line input is being interpreted directly, even though it is
  976. not really the case that a specific program is being compiled, there still
  977. exist the distinctions between run-time and compile-time.
  978.  
  979. In most cases at the command line words are executed at once, so the moment
  980. when the command line is actually executed is RUN-TIME for these words.
  981.  
  982. However, if the command line contains a colon definition, the words which
  983. are compiled within that definition will have their COMPILE-TIME as the
  984. command line is executed.
  985.  
  986. Here we only want to introduce you to the general concepts of run-time and
  987. compile-time: elsewhere in the tutorials we give specific instances where
  988. it is vital to understand the distinction between functions being executed
  989. at compile-time and run-time.
  990.  
  991. We will just mention here that HeliOS has many functions which allow you to
  992. control completely the action of all words at run-time and compile-time,
  993. allowing you to customise the process of compilation as required.
  994.  
  995. One other interesting and important feature of certain special HeliOS words
  996. is that they can automatically "sense" whether they are in "compile mode"
  997. within a colon definition, or are being executed directly, and change their
  998. behaviour accordingly.
  999.  
  1000. These words are very useful, and are called STATE-SENSITIVE functions.
  1001.  
  1002. The name "state-sensitive" is used because HeliOS, like FORTH, uses an
  1003. internal system variable called "STATE" to set whether the HeliOS system
  1004. is in COMPILE-MODE or EXECUTE-MODE.  You can get the value of this STATE
  1005. variable (using the expression "STATE @L") and use this in conjunction with
  1006. other special functions to generate your own special state sensitive words.
  1007.  
  1008. If you are brave, that is......
  1009.  
  1010.  
  1011. ----------------------
  1012. The Dictionary pointer
  1013. ----------------------
  1014.  
  1015. The HeliOS Dictionary memory space always has a current "top" position
  1016. pointer which specifies the next free memory location in the Dictionary.
  1017.  
  1018. As the Dictionary is used this "Dictionary Pointer" is gradually advanced
  1019. until finally the Dictionary space is full.
  1020.  
  1021. The current Dictionary Pointer is stored in a HeliOS system variable called
  1022. "DP" and is always available by simply using the expression:
  1023.  
  1024. DP @L
  1025.  
  1026. Because this is quite a commonly used function, HeliOS provides a single
  1027. word to access the current Dictionary Pointer: this word is "HERE".
  1028.  
  1029. So
  1030.  
  1031. HERE
  1032.  
  1033. is directly equivalent to
  1034.  
  1035. DP @L
  1036.  
  1037. and both return the current first free cell in Dictionary memory space.
  1038.  
  1039.  
  1040. --------------
  1041. Using "CREATE"
  1042. --------------
  1043.  
  1044. If you wish to create data tables, string buffers etc. within the HeliOS
  1045. dictionary, it is very easy and convenient to use CREATE or CREATEL.
  1046.  
  1047. What happens when you use these functions is that you create a new word
  1048. which when executed will return the address of the next dictionary space.
  1049.  
  1050. For example, you might use:
  1051.  
  1052. CREATE MyTable            ; Create new word
  1053. 1 ,                       ; Start of data table
  1054. 2 ,
  1055. 3 ,
  1056. 4 ,
  1057.  
  1058. When you subsequently use the word "MyTable", the 16-bit dictionary address
  1059. of the stored value "1" (the first location of the allotted table), will
  1060. be returned.
  1061.  
  1062. Note here the use of the simple and convenient word "," which simply stores
  1063. a data value in the next free location within the HeliOS Dictionary memory
  1064. space, then advances the Dictionary Pointer to the next position.
  1065.  
  1066.  
  1067. Notice that CREATE can be used to make a standard variable, like this:
  1068.  
  1069. CREATE MyVariableName
  1070.  
  1071. 0 ,
  1072.  
  1073. which is equivalent to
  1074.  
  1075. 0 VARIABLE MyVariableName
  1076.  
  1077.  
  1078. Here are a few useful points to note about CREATE.
  1079.  
  1080. 1. The new word specified using CREATE will always return a pointer to the
  1081.    current next free Dictionary space when CREATE was used.
  1082.  
  1083. 2. The words "ALLOT" and "," (and related functions) can be used after
  1084.    CREATE to allocate Dictionary memory and advance the Dictionary Pointer,
  1085.    thus effectively allowing the construction of convenient "protected"
  1086.    data space.
  1087.  
  1088. 3. After using CREATE, the word HERE will return a pointer to the Dictionary
  1089.    address which will be returned by the word just created by CREATE.
  1090.  
  1091. 4. Using CREATE only sets up a new word name header which when executed will
  1092.    return a pointer to the current Dictionary top free space.
  1093.  
  1094. 5. Using CREATE does NOT allocate any Dictionary space or perform any other
  1095.    function to "protect" or affect in any way the Dictionary address which
  1096.    will be returned by the newly CREATED word.
  1097.  
  1098.  
  1099. Another example of using CREATE might be:
  1100.  
  1101. CREATEL MyName $ This is my name$
  1102.  
  1103. Using the word "MyName" will now return a 32-bit pointer to the string "This
  1104. is my name".
  1105.  
  1106.  
  1107. Another example might be:
  1108.  
  1109. CREATEL MyNameTable
  1110.  
  1111. $ My name 1$
  1112. $ My name 2$
  1113. $ My name 3$
  1114. $ My name 4$
  1115.  
  1116. You can see what this does.....(It creates a 32-bit addressed string array)
  1117.  
  1118. Of course you can also use VARIABLE etc. to do similar things, but the use
  1119. of CREATE is very convenient and worth adding to your repertoire.
  1120.  
  1121. Remember that although CREATE is very convenient to use, it does have the
  1122. disadvantage that data structures created using this method use precious
  1123. Dictionary space.
  1124.  
  1125. This does not matter in small programs, but you must be careful not to use
  1126. CREATE too liberally for large data structures or in very large programs.
  1127.  
  1128. See the next section for another reason to take care when creating data
  1129. structures in the Dictionary memory area.......
  1130.  
  1131.  
  1132. -------------------------------------------------------------------
  1133. Run-time initialisation of data structures within Dictionary memory
  1134. -------------------------------------------------------------------
  1135.  
  1136. It is very important to understand that any 32-bit pointers referenced
  1137. within the HeliOS Dictionary must always be initialised in run-time code.
  1138.  
  1139. Look at this a fragment of HeliOS code:
  1140.  
  1141. CREATEL MyDataStructure1
  1142.  
  1143. 0. D, \ <---------------------------
  1144. 1 ,                                 |
  1145. 2 ,                                 |
  1146. 3 ,                                 | Points directly to previous structure
  1147.                                     |
  1148. CREATEL MyDataStructure2            |
  1149.                                     |
  1150. MyDataStructure1 D, \ --->----------
  1151. 1 ,
  1152. 2 ,
  1153. 3 ,
  1154.  
  1155. ( Notice that the above code is not within a colon definition, and will
  1156.   execute as the program is initially compiled )
  1157.  
  1158. : MyProgram
  1159.  
  1160. MyProgram1
  1161. MyProgram2
  1162. MyProgram3
  1163. etc.
  1164. etc.
  1165. ;
  1166.  
  1167. MyProgram
  1168.  
  1169. Here you can see that the first field of MyDataStructure2 contains a
  1170. 32-bit pointer to the first data structure, MyDataStructure1.
  1171.  
  1172. Obviously this pointer is valid, and if you went on to compile and run the
  1173. program containing this fragment, the pointer would work correctly: we have
  1174. literally "defined" the first field of the second data structure to point
  1175. to the first structure.
  1176.  
  1177. No problem!
  1178.  
  1179. Or is there......?
  1180.  
  1181. There is a trap hidden here, which you must be very wary of.
  1182.  
  1183. If you were to save the compiled program as a module to be used with the
  1184. HeliOS executive program, you would indeed have a very bad problem.
  1185.  
  1186. The problem is that the "MyDataStructure1" pointer would actually only have
  1187. been initialised in the code fragment you saw above, which would execute at
  1188. COMPILE-TIME (when the program was compiled before being saved as a HeliOS
  1189. code module).
  1190.  
  1191. Note that this pointer is an absolute 32-bit address, and would be valid
  1192. specifically and only for the position in memory where the software was
  1193. currently loaded (at compile-time).
  1194.  
  1195. If the code module is later loaded into a HeliOS system which has been
  1196. loaded into a different memory address (99% certainly the case!), notice
  1197. that this absolute 32-bit pointer will be incorrect!  The pointer was only
  1198. valid in the initial "compile" environment, and will no longer be valid in
  1199. the subsequent "execution" environment.
  1200.  
  1201. In other words, absolute pointers in HeliOS code modules are NOT RELOCATED
  1202. when a code module is reloaded by another HeliOS system.
  1203.  
  1204. This means that you MUST ensure that all 32-bit pointers are initialised
  1205. dynamically in RUN-TIME code.
  1206.  
  1207. Thus, in the startup code of your actual program, within a colon definition
  1208. WHICH WILL EXECUTE AT RUN-TIME, you must include a fragment of code like
  1209. this:
  1210.  
  1211. CREATEL MyDataStructure1
  1212.  
  1213. 0. D,
  1214. 1 ,
  1215. 2 ,
  1216. 3 ,
  1217.  
  1218. CREATEL MyDataStructure2
  1219.  
  1220. MyDataStructure1 D,
  1221. 1 ,
  1222. 2 ,
  1223. 3 ,
  1224.  
  1225. : InitMyDataStructure
  1226.  
  1227. MyDataStructure1 MyDataStructure2 D!L
  1228. ;
  1229.  
  1230. : MyProgram
  1231.  
  1232. InitMyDataStructure
  1233.  
  1234. MyProgram1
  1235. MyProgram2
  1236. MyProgram3
  1237. etc.
  1238. etc.
  1239. ;
  1240.  
  1241. MyProgram
  1242.  
  1243. Note the simple way that InitMyDataStructure is used to initialise the
  1244. pointer: MyDataStructure1 returns a 32-bit pointer to MyDataStructure1 at
  1245. run-time, and we simply use D!L to set this address into the first field
  1246. of MyDataStructure2.
  1247.  
  1248. So, an important "golden rule" is:
  1249.  
  1250. * ALWAYS INITIALISE ALL POINTERS AND VARIABLES DYNAMICALLY IN RUN-TIME CODE
  1251.  
  1252.  
  1253. There are two examples in the "HeliOS:Source" directory which demonstrate
  1254. the use of run-time initialisation of linked data structures in Dictionary
  1255. memory: you might like to look at these examples.
  1256.  
  1257. These are the files "IntuitionGadgets.src" and "IntuitionMenus.src", where
  1258. typical Intuition linked data structures for gadgets and menus are created
  1259. within the HeliOS Dictionary space.
  1260.  
  1261.  
  1262. ----------------------------------------------
  1263. Easy ways of setting up text strings in HeliOS
  1264. ----------------------------------------------
  1265.  
  1266. It is most convenient, unless Dictionary space is in short supply, to set
  1267. up text strings within the HeliOS Dictionary memory space.
  1268.  
  1269. There are various ways of doing this, and below we give examples of some of
  1270. the easiest and most commonly used.
  1271.  
  1272.  
  1273. Strings which return 16-bit addresses:
  1274.  
  1275.  
  1276. 20 $VARIABLE MyString
  1277.  
  1278. -> Allocates space for a 20 character counted string, initialised to null.
  1279.  
  1280.  
  1281. $CONSTANT MyString $Contents of MyString$
  1282.  
  1283. -> Creates a counted string with contents "Contents of MyString".
  1284.  
  1285.  
  1286. CREATE MyString $ $Contents of MyString$
  1287.  
  1288. -> Creates a counted string with contents "Contents of MyString".
  1289.  
  1290.  
  1291. CREATE MyString <$ $Contents of MyString$
  1292.  
  1293. -> Creates an uncounted string with contents "Contents of MyString".
  1294.  
  1295.  
  1296.  
  1297. Strings which return 32-bit addresses:
  1298.  
  1299.  
  1300. 20 $VARIABLEL MyString
  1301.  
  1302. -> Allocates space for a 20 character counted string, initialised to null.
  1303.  
  1304.  
  1305. $CONSTANTL MyString $Contents of MyString$
  1306.  
  1307. -> Creates a counted string with contents "Contents of MyString".
  1308.  
  1309.  
  1310. CREATEL MyString $ $Contents of MyString$
  1311.  
  1312. -> Creates a counted string with contents "Contents of MyString".
  1313.  
  1314.  
  1315. CREATEL MyString <$ $Contents of MyString$
  1316.  
  1317. -> Creates an uncounted string with contents "Contents of MyString".
  1318.  
  1319.  
  1320. If you simply want a string when typing at the command line it is easiest
  1321. to use the word $NEXTL as follows:
  1322.  
  1323. $NEXTL Contents_of_MyString
  1324.  
  1325. Notice that this word is quick and easy, but has the disadvantage that
  1326. it requires that the string has no internal spaces: in fact $NEXTL will
  1327. simply get the next word in the input stream delimited by spaces.
  1328.  
  1329. If you want a string which includes spaces when typing at the command line
  1330. it is easiest to use $DELNEXTL which uses the system string delimiter:
  1331.  
  1332. $DELNEXTL $Contents of MyString$
  1333.  
  1334. Both these words return counted strings, and if you require an uncounted
  1335. string it is easiest to simply increment the counted string pointer by one
  1336. to skip the count byte.
  1337.  
  1338. Both these words return PADL, where the string has been stored, so if you
  1339. want to preserve the string for future use you must move it from PADL to
  1340. somewhere safer, because PAD is used internally by HeliOS in many of its
  1341. string manipulations.
  1342.  
  1343.  
  1344. ----------------------------------
  1345. The "Code Field Address", or "CFA"
  1346. ----------------------------------
  1347.  
  1348. This is part of the internal working of HeliOS which is very useful for you
  1349. to know about, as you will see later.
  1350.  
  1351. Originally, in FORTH, all words had the following sections:
  1352.  
  1353. Name Field Address      (= "NFA") -> The address of the word name itself
  1354.  
  1355. Code Field Address      (= "CFA") -> The address of the word's execution
  1356.                                      code
  1357.  
  1358. Parameter Field Address (= "PFA") -> The address of the word's "body"
  1359.  
  1360. Details of how these internals work need not worry you, especially since
  1361. HeliOS is no longer internally constructed in the same way as FORTH, but
  1362. you will from time to time see references to these names in documentation.
  1363.  
  1364. In HeliOS, unlike FORTH, the various parts of any word are not stored in
  1365. the same memory area, and although HeliOS words do still have NFA, PFA and
  1366. CFA fields, these are not strictly the same as the old FORTH concepts.
  1367.  
  1368. The really useful thing in all this is the "CFA", because you can make use
  1369. of this address to EXECUTE a command indirectly.
  1370.  
  1371. You do not need to know details of internal working, but you do need to
  1372. know two important things:
  1373.  
  1374. 1. How to get the CFA of any word
  1375.  
  1376. 2. How to use the CFA to execute a word indirectly
  1377.  
  1378.  
  1379. To get the CFA of any word, you can use these HeliOS functions:
  1380.  
  1381.      FIND          ( _ _ _ CFA or 0 )
  1382.  
  1383.                    Used in the form:
  1384.  
  1385.                    FIND MyWord
  1386.  
  1387.                    to search the dictionary for "MyWord".
  1388.  
  1389.                    If not found flag 0 is returned, otherwise the CFA of
  1390.                    MyWord is returned.
  1391.  
  1392.                    This is a state sensitive word and performs its function
  1393.                    within a colon definition by compiling the found CFA as
  1394.                    a literal.
  1395.  
  1396.      LATESTCFA     ( _ _ _ CFA )
  1397.  
  1398.                    Returns CFA of last word in current vocabulary.
  1399.  
  1400.      MYSELF        ( _ _ _ CFA )
  1401.  
  1402.                    Used within colon definitions to compile the CFA of the
  1403.                    word being defined for recursive functions.
  1404.  
  1405.      '             ( _ _ _ PFA )                    "tick"
  1406.  
  1407.                    Used in the form:
  1408.  
  1409.                    ' MyWord
  1410.  
  1411.                    where MyWord is any word in the dictionary.
  1412.  
  1413.                    Searches dictionary for MyWord and if found returns PFA.
  1414.  
  1415.                    If not found an error is reported.
  1416.  
  1417.                    This is a state sensitive word and performs its function
  1418.                    within a colon definition by compiling the found PFA as
  1419.                    a literal.
  1420.  
  1421.      CFA           ( PFA _ _ _ CFA )
  1422.  
  1423.                    Converts HeliOS word PFA on stack to CFA.
  1424.  
  1425. Obviously you can only get the CFA of a word after it has been defined, but
  1426. the special case of MYSELF is interesting in that it allows you to obtain
  1427. a reference to the CFA of the current word being compiled, thus giving the
  1428. facility for employing recursion (this is an advanced operation and is only
  1429. mentioned here for the sake of interest).
  1430.  
  1431.  
  1432. Important note:
  1433.  
  1434. There is a VERY IMPORTANT proviso which you must remember when getting the
  1435. CFA of any HeliOS word:
  1436.  
  1437. * YOU CAN ONLY FIND THE CFA OF A NAMED HELIOS FUNCTION IF THE VOCABULARY
  1438.   INFORMATION IS PRESENT
  1439.  
  1440. This means that:
  1441.  
  1442. * ALL "CFA FINDING" OPERATIONS MUST BE PERFORMED BY COMPILE-TIME CODE AND
  1443.   NEVER BY RUN-TIME CODE
  1444.  
  1445. This is a subtle but vitally important point and needs further explanation:
  1446.  
  1447. When a program is being compiled or interpereted the HeliOS system keeps on
  1448. line a vocabulary word name list so it can locate any specified word.
  1449.  
  1450. The functions "'" and "FIND" make use of this vocubulary name listing to
  1451. find the PFA or CFA of a word at compile time.
  1452.  
  1453. If you are subsequently running a program using the stand-alone HeliOS
  1454. executive module, the vocabulary name list is no longer present, so your
  1455. program code cannot use "'", or "FIND" functions to get a word CFA.
  1456.  
  1457. This means that you must perform all CFA finding operations in code which
  1458. runs at COMPILE-TIME, as the program is actually being compiled, when the
  1459. full vocabulary information is present.
  1460.  
  1461. The best way of doing this is to find all required CFAs at compile time and
  1462. store them into variables which can be accessed at RUN-TIME.
  1463.  
  1464. For example:
  1465.  
  1466. 0 VARIABLE (FUNCTION1)                          <- COMPILE-TIME code
  1467. 0 VARIABLE (FUNCTION2)                          <- COMPILE-TIME code
  1468. 0 VARIABLE (FUNCTION3)                          <- COMPILE-TIME code
  1469. etc.
  1470. etc.
  1471.  
  1472. : FUNCTION1  PLACE YOUR PROGRAM CODE HERE ;
  1473.              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^       <- RUN-TIME code
  1474. : FUNCTION2  PLACE YOUR PROGRAM CODE HERE ;
  1475.              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^       <- RUN-TIME code
  1476. : FUNCTION3  PLACE YOUR PROGRAM CODE HERE ;
  1477.              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^       <- RUN-TIME code
  1478. etc.
  1479. etc.
  1480.  
  1481. FIND FUNCTION1 (FUNCTION1) !                    <- COMPILE-TIME code
  1482. FIND FUNCTION2 (FUNCTION2) !                    <- COMPILE-TIME code
  1483. FIND FUNCTION3 (FUNCTION3) !                    <- COMPILE-TIME code
  1484. etc.
  1485. etc.
  1486.  
  1487. Remember:
  1488.  
  1489. * NO OPERATIONS WHICH REQUIRE ACCESS TO THE VOCABULARY LIST ARE POSSIBLE
  1490.   WITHIN "RUN-TIME" CODE
  1491.  
  1492.  
  1493. Having acquired the CFA of a word, you can use the following HeliOS words
  1494. to execute the word:
  1495.  
  1496.      EXECUTE       ( CFA _ _ _ )
  1497.  
  1498.                    Executes word whose CFA is on stack.
  1499.  
  1500.      @EXECUTE      ( a1 _ _ _ )
  1501.  
  1502.                    Executes word whose CFA is stored at a1.
  1503.  
  1504. This facility for indirect execution has many uses, the most important of
  1505. which, as we will see next, is "Vectored Execution".
  1506.  
  1507.  
  1508. ------------------
  1509. Vectored Execution
  1510. ------------------
  1511.  
  1512. This is a very important technique which you will certainly need to use
  1513. often in your HeliOS programs.
  1514.  
  1515. The term "Vectored Execution" refers to the technique of executing HeliOS
  1516. functions by reference to indirect pointers.  The idea here is that you can
  1517. store the CFA of a word in a variable, or a table, and execute the word by
  1518. referencing the stored CFA.
  1519.  
  1520. Here are a few a simple ways you could use this.
  1521.  
  1522. 1. Changing the operation of an already compiled word.
  1523.  
  1524. You could make word called PrintName as follows:
  1525.  
  1526. 0 VARIABLE CurrentName                 \ Set up a dummy variable
  1527.  
  1528. : PrintName CurrentName @EXECUTE ;     \ Create command word
  1529.  
  1530. : Name1 ." Name1" ;                    \ Create Name1
  1531.  
  1532. LATESTCFA CurrentName !                \ Store CFA of Name1 as CurrentName
  1533.  
  1534. This will give the function "PrintName" the action of printing "Name1", and
  1535. PrintName can be incorporated in whatever routine you wish.  At any time
  1536. later you can change the operation of PrintName very easily: for example,
  1537. you could change it like this:
  1538.  
  1539. : Name2 ." Name2" ;                    \ Create Name2
  1540. : Name3 ." Name3" ;                    \ Create Name3
  1541. : Name4 ." Name4" ;                    \ Create Name4
  1542.  
  1543. FIND Name2 CurrentName !               \ Store CFA of Name2 as CurrentName
  1544.  
  1545. After this PrintName would print "Name2".
  1546.  
  1547. or
  1548.  
  1549. FIND Name4 CurrentName !               \ Store CFA of Name4 as CurrentName
  1550.  
  1551. After this PrintName would print "Name4".
  1552.  
  1553. etc.
  1554.  
  1555.  
  1556. 2. Using selective execution tables.
  1557.  
  1558. You can conditionally execute one of a set of functions by reference to a
  1559. table.
  1560.  
  1561. Here is an example:
  1562.  
  1563. : Name1 ." Name1" ;                    \ Create Name1
  1564. : Name2 ." Name2" ;                    \ Create Name2
  1565. : Name3 ." Name3" ;                    \ Create Name3
  1566. : Name4 ." Name4" ;                    \ Create Name4
  1567. : Name5 ." Name5" ;                    \ Create Name5
  1568.  
  1569. CREATE MyNameTable
  1570.  
  1571. FIND Name1 ,                          \ Store CFA of Name1
  1572. FIND Name2 ,                          \ Store CFA of Name2
  1573. FIND Name3 ,                          \ Store CFA of Name3
  1574. FIND Name4 ,                          \ Store CFA of Name4
  1575. FIND Name5 ,                          \ Store CFA of Name5
  1576.  
  1577. 0 VARIABLE CurrentFunctionNumber
  1578.  
  1579. : GetName MyNameTable CurrentFunctionNumber @ 2* + @EXECUTE ;
  1580.  
  1581. In this example, "GetName" will have its operation controlled by the number
  1582. stored in the variable "CurrentFunctionNumber".
  1583.  
  1584. Note that the value of CurrentFunctionNumber has been doubled (using 2*) in
  1585. the above code, because each entry in the CFA table is 2 bytes in length,
  1586. so all offsets into the table must be in multiples of 2 bytes.
  1587.  
  1588. This technique of executing CFAs from a table can be used for conditional
  1589. execution in many circumstances, and in general is much more powerful than
  1590. using lots of nested conditional IF...THEN statements to carry out actions
  1591. based on the value of a variable.
  1592.  
  1593.  
  1594. 3. Using words before they have been defined.
  1595.  
  1596. This is the most important use of vectored execution, and is an absolutely
  1597. vital technique which you will often need in your HeliOS programs.
  1598.  
  1599. Normally you can only use a word AFTER it has been created, and this often
  1600. imposes quite severe limitations on the way you organise your code.  This
  1601. in itself is not too bad, but there can be occasions where you need to have
  1602. functions which refer to each other: this is obviously impossible because
  1603. the first word created cannot call the second word because it has not yet
  1604. been defined.
  1605.  
  1606. This is where vectored execution can be useful, because it allows you to
  1607. define a set of executable variables at the start of a program which can
  1608. be referred to by intermediate functions and then set up at the end of the
  1609. program to contain the CFAs of any intermediate HeliOS words.
  1610.  
  1611. Here is a trivial example to illustrate the general idea: you will find
  1612. more complex examples in the source code example files provided.
  1613.  
  1614. 0 VARIABLE (MyFunction1)
  1615. 0 VARIABLE (MyFunction2)
  1616. 0 VARIABLE (MyFunction3)
  1617.  
  1618. : MyFunction1  (MyFunction2) @EXECUTE ;
  1619. : MyFunction2  (MyFunction3) @EXECUTE ;
  1620. : MyFunction3  ." Hello" ;
  1621.  
  1622. FIND MyFunction1 (MyFunction1) !
  1623. FIND MyFunction2 (MyFunction2) !
  1624. FIND MyFunction3 (MyFunction3) !
  1625.  
  1626. Notice that we used brackets surrounding the function names for the CFA
  1627. storage variables.  This is merely a matter of personal choice, but it is
  1628. quite a useful idea to use some such consistent naming convention.
  1629.  
  1630.  
  1631. -----------------------
  1632. Error handling routines
  1633. -----------------------
  1634.  
  1635. It is useful to have a consistent method of dealing with program errors.
  1636.  
  1637. You can easily create a custom error handler which prints an error message
  1638. and closes down your program in a civilised fashion, deallocating all the
  1639. resources which may have been opened before the error occurred.
  1640.  
  1641. A good error handler allows all errors to be routed via a comprehensive
  1642. sequential closedown routine, and this can be done easily using the HeliOS
  1643. system customisable error handler word ERROR", which can be customised
  1644. using SETERROR".
  1645.  
  1646. When ERROR" senses an error it prints an associated error text message
  1647. (which it gets from the next part of the input stream delimited by a '"'
  1648. character) and then ABORTS program execution.
  1649.  
  1650. This is OK as far as it goes, but it does not close down specific things
  1651. related to your program, so you need to customise ERROR" to do a little
  1652. more intelligent work.
  1653.  
  1654. To do this you must first create a function which closes down everything
  1655. your program opened: the error handler will use this function to end your
  1656. program tidily.
  1657.  
  1658. If you write such a function (called CLOSEDOWN for ease of reference here)
  1659. you must make it intelligent enough to do two important things:
  1660.  
  1661. 1. Close down everything in the exact reverse order in which it was created
  1662.    to help avoid memory fragmentation problems.
  1663.  
  1664. 2. Check to see what has or has not yet been opened and only close down
  1665.    what is required.  This is easy to do by having variables which are only
  1666.    set when an associated resource has been opened: for example, you could
  1667.    have a window handle variable which would be null until you filled it in
  1668.    when the window was actually opened.
  1669.  
  1670. 3. It is a good idea if the CLOSEDOWN routine finally resets ERROR" to the
  1671.    standard system function, using RESETERROR".
  1672.  
  1673.  
  1674. Here is a short general example of setting up a custom error handler.
  1675.  
  1676.   0. DVARIABLE MYSCREEN
  1677.   0. DVARIABLE MYWINDOW
  1678.  
  1679.   0 VARIABLE (CLOSEDOWN)
  1680.   0 VARIABLE (MYCLOSEDOWNERROR)
  1681.  
  1682.   : MYCLOSEDOWNERROR                             \ Action on error
  1683.  
  1684.   IF                                             \ If there is an error
  1685.     CR                                           \ Move down
  1686.     CR
  1687.     TYPE                                         \ Type error message
  1688.     CR                                           \ Move down
  1689.     CR
  1690.     ." Press <Space> to quit!"                   \ Print message
  1691.     CR                                           \ Move down
  1692.     CR
  1693.     WAITSPACE                                    \ Wait for <SPACE>
  1694.     (CLOSEDOWN) @EXECUTE                         \ Execute close down
  1695.     QUIT                                         \ QUIT back to HelioS
  1696.   ELSE
  1697.     DDROP                                        \ No error, so just DDROP
  1698.   THEN
  1699.   ;
  1700.  
  1701.   : CLOSEDOWN                                    \ Closes down resources
  1702.  
  1703.   MYWINDOW D@
  1704.   D0<>                                           \ ? Close window
  1705.   IF
  1706.     MYWINDOW D@ CLOSEWINDOW
  1707.   THEN
  1708.  
  1709.   MYSCREEN D@                                    \ ? Close screen
  1710.   D0<>
  1711.   IF
  1712.     MYSCREEN D@ CLOSESCREEN
  1713.   THEN
  1714.  
  1715.   RESETERROR"                                    \ Reset system ERROR"
  1716.   ;
  1717.  
  1718.   FIND CLOSEDOWN         (CLOSEDOWN) !           \ Set execution variable
  1719.   FIND MYCLOSEDOWNERROR  (MYCLOSEDOWNERROR) !    \ Set execution variable
  1720.  
  1721.   : MYPROGRAM
  1722.  
  1723.    (MYCLOSEDOWNERROR) SETERROR"                  \ Set custom ERROR"
  1724.  
  1725.    LIT$ $MyScreen$ 640 256 4 OPENSCREEN          \ Try to open screen
  1726.  
  1727.    DFLAG0= ERROR" Failed to open screen!"        \ Test for error
  1728.  
  1729.    SCREEN1 D!                                    \ Success, so store
  1730.  
  1731.    etc. etc.
  1732.   ;
  1733.  
  1734. See the "Dictionary.doc" for full details of all related functions:
  1735.  
  1736. ERROR", ERROR"FUNCTION, RESETERROR", SETERROR".
  1737.  
  1738.  
  1739. ----------------------
  1740. Using the Return stack
  1741. ----------------------
  1742.  
  1743. HeliOS, like FORTH, has a secondary stack which is used internally by the
  1744. system for various purposes: this is called the "Return" stack because one
  1745. of its main functions is to store return pointers during nested command
  1746. threading operations.
  1747.  
  1748. The Return stack will be familiar to FORTH users, but remember that HeliOS
  1749. uses the Return stack differently in its internal operation, so do not rely
  1750. on being able to do the same "tricks" with the Return stack that you might
  1751. do in traditional FORTH.
  1752.  
  1753. The Return stack can be used as a fast auxiliary data storage space for
  1754. "local" data during the execution of a colon definition.  However, you
  1755. MUST ensure that the state of the Return stack is left unchanged overall,
  1756. and that it is restored to exactly the same status at the end of any colon
  1757. definition function as it had when the function started.
  1758.  
  1759. There are easy to use and very fast words for moving data between the HeliOS
  1760. stack and the Return stack, in both directions.
  1761.  
  1762. The Return stack also has the useful property that within loop constructs it
  1763. stores the loop index and loop limit: this means that you can use the Return
  1764. stack to get loop indices and generally manipulate loops in special ways.
  1765.  
  1766. The use of the Return stack in HeliOS is very similar to FORTH from the
  1767. programmers point of view, and in many ways HeliOS seems to be using the
  1768. Return stack exactly like FORTH.  However, HeliOS does use the Return stack
  1769. internally in special ways, so do not assume that standard FORTH usage is
  1770. always applicable unless specifically stated.
  1771.  
  1772. There are several operators which allow you to access numbers on the Return
  1773. stack and to move numbers between the Return stack and the HeliOS stack:
  1774.  
  1775.      >R    ( n1 _ _ )         Move top of stack onto return stack.
  1776.  
  1777.      D>R   ( d1 _ _ )         Move top of stack d-number onto return stack.
  1778.  
  1779.      DDUP>R ( d1 _ _ d1 )     DDUP and move tos d-number onto return stack.
  1780.  
  1781.      DI    ( _ _ d1 )         Get copy of top d-number from return stack.
  1782.  
  1783.      DI'   ( _ _ d1 )         Get copy ofsecond d-number on return stack.
  1784.  
  1785.      DJ    ( _ _ d1 )         Get copy of third d-number on return stack.
  1786.  
  1787.      DJ'   ( _ _ d1 )         Get copy of fourth d-number on return stack.
  1788.  
  1789.      DR>   ( _ _ d1 )         Remove top r-stack d-number onto HeliOS stack.
  1790.  
  1791.      DUP>R ( n1 _ _ n1 )      DUP and move top of stack onto return stack.
  1792.  
  1793.      I     ( _ _ n1 )         Get copy of top number on return stack.
  1794.  
  1795.      I'    ( _ _ n1 )         Get copy of second number on return stack.
  1796.                                        ( = 1st loop limit. )
  1797.      J     ( _ _ n1 )         Get copy of third number on return stack.
  1798.                                        ( = 2nd loop index. )
  1799.      J'    ( _ _ n1 )         Get copy of fourth number on return stack.
  1800.                                        ( = 2nd loop limit. )
  1801.      K     ( _ _ n1 )         Get copy of fifth number on return stack.
  1802.                                        ( = 3rd loop index. )
  1803.      K'    ( _ _ n1 )         Get copy of sixth number on return stack.
  1804.                                        ( = 3rd loop limit. )
  1805.      R>    ( _ _ n1 )         Remove top of return stack onto HeliOS stack.
  1806.  
  1807.      R!    ( l1 _ _ )         Sets Return stack pointer to l1.
  1808.  
  1809.      RP!   ( _ _ )            Initialise return stack.
  1810.  
  1811.      RP@   ( _ _ l1 )         Return address of current return stack top.
  1812.  
  1813.  
  1814. The most useful feature of the Return stack is that it can be used as a
  1815. temporary store within the execution of a colon definition.
  1816.  
  1817. If your stack parameter manipulations are getting complicated it is very
  1818. useful to be able to move numbers off the HeliOS stack onto the Return
  1819. stack.  In effect you can use the Return stack as a kind of temporary
  1820. storage data structure, and this is far faster and more efficient than
  1821. using complicated HeliOS stack manipulations or using storage variables.
  1822.  
  1823. The Return stack is a simple linear "last-in-first-out" structure, just
  1824. like the data stack, so the rules for manipulating it are just like the
  1825. ones you are used to using for the main HeliOS stack.  Remember however
  1826. that whatever numbers you store on the Return stack must be removed again
  1827. before you get to the end of the current word definition: you cannot use
  1828. the Return stack to pass arguments from one word to another.
  1829.  
  1830. To see how the Return stack might be used to make parameter manipulation
  1831. easier, imagine you have to write a short routine to solve the following
  1832. equation:
  1833.  
  1834. ax² + bx + c
  1835.  
  1836. Assume that you start with all four parameter values on the stack in the
  1837. following order:
  1838.  
  1839. ( a b c x - - - )
  1840.  
  1841. First you might factor out the equation as:
  1842.  
  1843. ax² + bx + c = x(ax+b)+c
  1844.  
  1845. Now look at one way of breaking down the required operation:
  1846.  
  1847. OPERATOR        DATA STACK      RETURN STACK
  1848.  
  1849.                   a b c x
  1850.  
  1851.   >R              a b c           x
  1852.  
  1853.   SWAP ROT        c b a           x
  1854.  
  1855.   I               c b a x         x
  1856.  
  1857.   *               c b ax          x
  1858.  
  1859.   +               c (ax+b)        x
  1860.  
  1861.   R> *            c x(ax+b)
  1862.  
  1863.   +               x(ax+b)+c
  1864.  
  1865.  
  1866. Here is this sequence presented as a word definition:
  1867.  
  1868.   :  QUADRATIC  ( a b c x -- n )
  1869.  
  1870.      >R
  1871.      SWAP ROT
  1872.      I
  1873.      *
  1874.      +
  1875.      R> *
  1876.      +
  1877.   ;
  1878.  
  1879. Now test it:
  1880.  
  1881. 2 7 9 3  QUADRATIC
  1882.  
  1883. Result ->  48
  1884.  
  1885. Perhaps you would like to try to solve this programming task using your
  1886. own new method to see if you can do it more efficiently.
  1887.  
  1888. Why not try to do it:
  1889.  
  1890. 1. Without using the return stack.
  1891.  
  1892. 2. Using the Return stack, but in a different way.
  1893.  
  1894.  
  1895. ---------------------
  1896. Using HeliOS includes
  1897. ---------------------
  1898.  
  1899. The documentation for the Amiga operating system uses a massive number of
  1900. symbolic values, and it is quite impractical to do extensive programming of
  1901. the operating system without using these symbols.  If you try to work by
  1902. using directly coded numeric values for all the Amiga symbols you will end
  1903. up making many mistakes and your code will be clumsy and unreadable.
  1904.  
  1905. In most languages you have to use the Amiga "Include files" to create an
  1906. on-line reference system for all the symbolic values: then you can type
  1907. the symbolic names in your code rather than numeric values.  This is often
  1908. implemented in a very slow and memory-greedy manner, and many programmers
  1909. prefer to define symbolic values directly in their own code to avoid having
  1910. the overhead of using the include files.
  1911.  
  1912. HeliOS has an ideal solution to this problem, with a compact, efficient,
  1913. and ultra-fast "precompiled include file" system.
  1914.  
  1915. See the documentation file "HeliOS:Docs/UserInterface/IncludeFiles.doc"
  1916. for details of how the HeliOS include system works.
  1917.  
  1918. Setting up the HeliOS "high-speed" precompiled include file system is so
  1919. easy, and this system is so fast in operation, that you should ALWAYS use
  1920. it: then you can include ANY Amiga symbol directly in your code by simply
  1921. typing its symbolic name.
  1922.  
  1923. You can configure the main HeliOS Interpreter/Editor system to start up
  1924. with default include files already installed automatically, and this is
  1925. recommended for everyday programming work.
  1926.  
  1927. However, if you want your programs to be compiled also from the stand-alone
  1928. HeliOS compiler you need to include specific lines in the program code to
  1929. load the include files during compilation, like this:
  1930.  
  1931.   \ *************************
  1932.   \ Load include symbol files
  1933.   \ *************************
  1934.   \
  1935.   \ Note: these "include files" are pre-compiled (for speed) versions of
  1936.   \ the full Amiga includes and the HeliOS system includes.
  1937.   \
  1938.   \ Uncomment the lines below for standalone compilation, but otherwise
  1939.   \ it is quicker to set these include files from the HeliOS menus
  1940.  
  1941.   AMIGAINCLUDE HeliOS:HeliOS_AmigaInclude
  1942.   USERINCLUDE  HeliOS:HeliOS_UserInclude
  1943.  
  1944. Notice how easy it is to use the two words AMIGAINCLUDE and USERINCLUDE to
  1945. set up the include system to load any specified precompiled include files.
  1946.  
  1947. Once the include files are set up, you can easily get symbolic values and
  1948. add new symbols from within the main HeliOS Interpreter/Editor program.
  1949.  
  1950. From within your program source code or the HeliOS interpreter command line
  1951. you can access any Amiga symbol by simply typing its name.
  1952.  
  1953. However there is one important thing to remember:
  1954.  
  1955. * The HeliOS include system can be set to return either 16-bit or 32-bit
  1956.   values on the HeliOS stack.
  1957.  
  1958.   To set the HeliOS include system to return 16-bit values you use the word
  1959.   WORDINCLUDE.
  1960.  
  1961.   To set the HeliOS include system to return 32-bit values you use the word
  1962.   LONGINCLUDE.
  1963.  
  1964. The default setting is always for 32-bit include values, and it is best to
  1965. avoid confusion and possible errors by always returning the system to this
  1966. default status as soon as you have finished using any 16-bit include values.
  1967.  
  1968. For example:
  1969.  
  1970.      INTUBASE            \ Put on the stack the 16-bit address
  1971.                          \ where the 32-bit pointer to Intuition
  1972.                          \ library base is stored
  1973.  
  1974.      WORDINCLUDE         \ Set include system to return 16-bit values
  1975.  
  1976.      _LVOViewAddress     \ Put on the stack the offset of the library
  1977.                          \ call "ViewAddress" as a 16-bit value
  1978.  
  1979.      LONGINCLUDE         \ Reset include system to default 32-bit setting
  1980.  
  1981.      LIBRARY             \ Call Intuition Library function to get
  1982.                          \ VIEW pointer
  1983.  
  1984.      D0RESULT            \ Get dummy register D0 value which is the
  1985.                          \ View address returned from the library call
  1986.  
  1987.  
  1988. Try experimenting with the include system at the command line in the HeliOS
  1989. interpreter until you are confident about the way the system works and in
  1990. particular the use of WORDINCLUDE and LONGINCLUDE.
  1991.  
  1992.  
  1993. -----------------------
  1994. Calling Amiga libraries
  1995. -----------------------
  1996.  
  1997. This is very easy in HeliOS, and you should consult the "Dictionary.doc"
  1998. for a full explanation: however, here we will include an example so that
  1999. you can see the direct relationship between an assembly language library
  2000. call and one done in HeliOS.
  2001.  
  2002. Here are two examples of the same library call, one in assembler and the
  2003. other in HeliOS:
  2004.  
  2005. Assembler:
  2006.  
  2007. DOSBASE     dc.l  0    ; Initialised to DOS library base by startup code
  2008.  
  2009. CONFILE     dc.l  0
  2010.  
  2011. CON         dc.b 'CON:0/12/640/200/HeliOS',0
  2012.  
  2013. OPENCON
  2014.             move.l   #CON,D1
  2015.             move.l   #MODE_NEWFILE,D2
  2016.             move.l   DOSBASE,A6
  2017.             jsr      _LVOOpen(A6)
  2018.             move.l   D0,CONFILE
  2019.             rts
  2020.  
  2021. HeliOS:
  2022.  
  2023. CREATEL CON <$ CON:0/12/640/200/HeliOS$
  2024.  
  2025. 0. DVARIABLE CONFILE
  2026.  
  2027. : OPENCON
  2028.  
  2029. CON           1 DREG D!
  2030. MODE_NEWFILE  2 DREG D!
  2031. DOSBASE
  2032. WORDINCLUDE   _LVOOpen   LONGINCLUDE  LIBRARY
  2033. D0RESULT CONFILE D!
  2034. ;
  2035.  
  2036.  
  2037. Now compare them line by line:
  2038.  
  2039. : OPENCON                                     ->   OPENCON
  2040.  
  2041. CON           1 DREG D!                       ->   move.l   #CON,D1
  2042.  
  2043. MODE_NEWFILE  2 DREG D!                       ->   move.l   #MODE_NEWFILE,D2
  2044.  
  2045. DOSBASE                                       ->   move.l   DOSBASE,A6
  2046.  
  2047. WORDINCLUDE   _LVOOpen   LONGINCLUDE  LIBRARY ->   jsr      _LVOOpen(A6)
  2048.  
  2049. D0RESULT CONFILE D!                           ->   move.l   D0,CONFILE
  2050.  
  2051. ;                                             ->   rts
  2052.  
  2053.  
  2054. Notice that HeliOS library calls directly mirror the way things are done
  2055. in assembly language, so you may easily adapt any information you find in
  2056. documentation or examples which refer to assembly language library calls.
  2057.  
  2058.  
  2059. As a final example, look at the alternative HeliOS version using the word
  2060. "LIBRARYL" instead of "LIBRARY":
  2061.  
  2062. : OPENCON
  2063.  
  2064. CON           1 DREG D!
  2065. MODE_NEWFILE  2 DREG D!
  2066. _LVOOpen
  2067. DOSBASE  LIBRARYL
  2068. D0RESULT CONFILE D!
  2069. ;
  2070.  
  2071.  
  2072. Notice two advantages here:
  2073.  
  2074. 1. We did not need to use WORDINCLUDE and LONGINCLUDE
  2075.  
  2076. 2. We have the function offset followed by the line "DOSBASE LIBRARYL", and
  2077.    this could conveniently be made into a predefined colon definition which
  2078.    would be applicable to ALL our DOS library calls.
  2079.  
  2080. We could make a word CALLDOS, like this:
  2081.  
  2082. : CallDOS DOSBASE LIBRARYL ;
  2083.  
  2084. Then we could say things like:
  2085.  
  2086. _LVOOpen  CallDOS
  2087. _LVOClose CallDOS
  2088. _LVORead  CallDOS
  2089.  
  2090. etc.
  2091. etc.
  2092.  
  2093. You can see from this example that careful structuring of HeliOS code can
  2094. improve functionality and readability.
  2095.  
  2096.  
  2097. --------------------------
  2098. Setting up loops in HeliOS
  2099. --------------------------
  2100.  
  2101. We have already looked at the use of IF...ELSE...THEN constructs to set up
  2102. conditional branching, and now we are going to learn how to implement loops
  2103. in HeliOS.
  2104.  
  2105. Loops are methods of repeatedly executing certain sections of code, and
  2106. broadly speaking, there are three kinds of loop construct:
  2107.  
  2108. 1. Counted loops which execute the loop code a predetermined number of times.
  2109.  
  2110. 2. Conditional loops which execute the loop code until a condition is met.
  2111.  
  2112. 3. Infinite loops which loop forever.....or almost....
  2113.  
  2114.  
  2115. -------------
  2116. Counted Loops
  2117. -------------
  2118.  
  2119. Let us first look at counted loops, which are probably the most common.
  2120.  
  2121. In HeliOS, counted loops are set up by specifying the "initial" and "limit"
  2122. values of a "loop index".  This loop index is given its initial value for
  2123. the first iteration of the loop, then each time the loop executes the loop
  2124. index is increased until it reaches the limit value, at which point the loop
  2125. finishes.
  2126.  
  2127. The loop index is incremented and checked against the loop limit each time
  2128. around at the END of the loop.  If the index is still LESS THAN the limit,
  2129. the loop will branch back to the start, but if the index is GREATER THAN
  2130. OR EQUAL TO the limit, the loop finishes and the code carries on past the
  2131. loop end point.
  2132.  
  2133. The HeliOS words which implement a simple counted loop are "DO" and "LOOP",
  2134. where DO specifies the start of the loop and LOOP specifies the loop-back
  2135. point.  The loop index and loop limit are provided as parameters to the
  2136. word "DO".  The loop index and loop limit can be read onto the stack while
  2137. a loop is executing, using the HeliOS words "I" and "I'" respectively.
  2138.  
  2139. Here are the definitions of DO and LOOP:
  2140.  
  2141.      DO            ( n1 n2 _ _ _ )
  2142.  
  2143.                    Where:
  2144.  
  2145.                    n1 = loop limit
  2146.                    n1 = loop index
  2147.  
  2148.                    Used in colon definitions to mark the start of and set up
  2149.                    a loop.
  2150.  
  2151.                    The loop limit n1 is pushed onto the return stack
  2152.                    followed by the loop index initial value n2.
  2153.  
  2154.                    The loop executes until the index is incremented by
  2155.                    LOOP to a value equal to or greater than the loop limit.
  2156.  
  2157.      LOOP          ( _ _ _ )
  2158.  
  2159.                    Used in colon definitions to mark the end of a loop.
  2160.  
  2161.                    The loop index is incremented and execution returns to
  2162.                    DO if index is still less than limit.
  2163.  
  2164. Note that a DO....LOOP construct MUST be defined within a colon definition.
  2165.  
  2166. Using this information we can construct a test word to enable us to examine
  2167. the behaviour of a loop in action.
  2168.  
  2169.  : LOOPTEST
  2170.  
  2171.  CR
  2172.  
  2173.  10 0               \ Loop limit followed by start index (note the order!)
  2174.  DO
  2175.    I . I' . CR      \ Print loop index followed by loop limit
  2176.  LOOP
  2177.  ;
  2178.  
  2179.  LOOPTEST
  2180.  
  2181. This will display the following results:
  2182.  
  2183. 0 10
  2184. 1 10
  2185. 2 10
  2186. 3 10
  2187. 4 10
  2188. 5 10
  2189. 6 10
  2190. 7 10
  2191. 8 10
  2192. 9 10
  2193.  
  2194. Notice that the loop index never reaches the value of the loop limit while
  2195. within the loop, because, as soon as the loop index equals the limit, the
  2196. loop ends.  As we said earlier, it is important to remember that the index
  2197. is incremented and compared to the loop limit AT THE END of each loop.
  2198.  
  2199. Look closely at the example and read the notes above until you are sure
  2200. about the way these simple counted loops work.
  2201.  
  2202. It is very important to really understand the mechanism of loops, so here
  2203. again is a step by step breakdown of what happens as HeliOS executes a loop.
  2204.  
  2205. 1.  The word "DO" removes the limit and index parameters from the HeliOS
  2206.     stack and stores them on the Return stack (with the index on top of the
  2207.     Return stack and the limit in second place).
  2208.  
  2209. 2.  HeliOS executes sequentially the words within the loop, up to the word
  2210.     "LOOP".
  2211.  
  2212. 3.  The word "LOOP" increments the loop index (on top of the Return stack)
  2213.     and then performs the following checks.
  2214.  
  2215.     * If the loop index is still less than the loop limit (second on the
  2216.       Return stack) the loop returns execution to immediately after "DO"
  2217.       and the loop repeats again.
  2218.  
  2219.     * If the loop index is greater than or equal to the loop limit the loop
  2220.       finishes.
  2221.  
  2222. 4.  When the loop finishes, the index and limit values are removed from
  2223.     the Return stack and code execution continues with the word following
  2224.     the word "LOOP".
  2225.  
  2226. Note that now you have information on how the loop works, you can trick the
  2227. loop mechanism by modifying the loop index and limit values on the Return
  2228. stack from within the loop if you wish.  This can give rise to many useful
  2229. techniques, and is perfectly safe once you know what you are doing.
  2230.  
  2231. You can set up loops with any range provided that the limit is higher than
  2232. the index, and remember that the index does not have to start at "0".
  2233.  
  2234. Look at this interesting example:
  2235.  
  2236. :  NEGLOOP  -230  -240  DO I .  LOOP  ;
  2237.  
  2238. NEGLOOP
  2239.  
  2240. will print out:
  2241.  
  2242. -240 -239 -238 -237 -236 -235 -234 -233 -232 -231
  2243.  
  2244. Notice that the index (-240) still starts as less than the limit (-230).
  2245.  
  2246. In many FORTH versions, if you specify the "DO" parameters such that the
  2247. index is greater than or equal to the loop limit at the start, the loop
  2248. will set off and recycle through the whole range of index values until it
  2249. equals the limit again.
  2250.  
  2251. HeliOS does not display this uncivilised behaviour, and will merely quit at
  2252. the end of the first loop if you make a mistake like this.
  2253.  
  2254. This brings us to an important point:
  2255.  
  2256. *  No matter what the starting parameters, a HeliOS loop will ALWAYS go
  2257.    through the intermediate code (or "body") of the loop at least once.
  2258.  
  2259. This is because no checking of the index amnd limit values is carried out
  2260. until the end of the loop is reached.
  2261.  
  2262. Another somewhat subtle point is that you can only use the words "I" and
  2263. "I'" to get the loop index and limit within the SAME colon definition in
  2264. which the loop is defined.  In other words, you cannot use "I" and "I'"
  2265. in any sub-words within the loop.
  2266.  
  2267. For example, the following code would not work correctly:
  2268.  
  2269. : PRINTINDEX I . ;
  2270.  
  2271. : TESTLOOP
  2272.  
  2273. 10 0
  2274. DO
  2275.   PRINTINDEX
  2276. LOOP
  2277. ;
  2278.  
  2279. The reason that this would fail is that the loop parameters are only at
  2280. the top of the Return stack in the "root" level of the colon definition
  2281. in which the loop is defined.  When HeliOS enters the word PRINTINDEX in
  2282. the above example the Return stack is used to store "Return" information
  2283. by the HeliOS system, so the words "I" and "I'" will no longer return the
  2284. actual loop parameters from the Return stack.
  2285.  
  2286. Of course, you can have loops within loops, and these are called "Nested
  2287. Loops".  Nested loops are just like ordinary loops, but there is a useful
  2288. way of getting at the loop parameters of an outer nested loop from inside
  2289. the inner nested loop.
  2290.  
  2291. This is done by using special Return stack operators ("J", "K" etc.) which
  2292. get the stack values for outer loops from BELOW the top two stack items.
  2293.  
  2294. For example, here are some useful Return stack operators to use in nested
  2295. loops:
  2296.  
  2297.      I     ( _ _ n1 )         Get copy of top number on return stack.
  2298.                                        ( = 1st loop index. )
  2299.      I'    ( _ _ n1 )         Get copy of second number on return stack.
  2300.                                        ( = 1st loop limit. )
  2301.      J     ( _ _ n1 )         Get copy of third number on return stack.
  2302.                                        ( = 2nd loop index. )
  2303.      J'    ( _ _ n1 )         Get copy of fourth number on return stack.
  2304.                                        ( = 2nd loop limit. )
  2305.      K     ( _ _ n1 )         Get copy of fifth number on return stack.
  2306.                                        ( = 3rd loop index. )
  2307.      K'    ( _ _ n1 )         Get copy of sixth number on return stack.
  2308.                                        ( = 3rd loop limit. )
  2309.  
  2310. Here is an interesting example of a nested loop:
  2311.  
  2312. : NESTLOOP
  2313.  
  2314.   SCRCLR
  2315.   0
  2316.   400 100
  2317.   DO
  2318.     1+ DUP GFXSETAPEN
  2319.     150 100
  2320.     DO
  2321.       J I GFXWRITE
  2322.     LOOP
  2323.   LOOP
  2324.   WAITSPACE
  2325. ;
  2326.  
  2327. NESTLOOP
  2328.  
  2329.  
  2330. Other useful function to use in counted loops are "/LOOP" and "+LOOP":
  2331. these words allow you to specify increments other than "1" for the loop
  2332. index for each loop cycle.
  2333.  
  2334. Here are the definitions of these words:
  2335.  
  2336.      +LOOP         ( n1 _ _ _ )
  2337.  
  2338.                    Used in colon definitions in the form:
  2339.  
  2340.                                  DO - - - - - n1 +LOOP
  2341.  
  2342.                    to implement a loop in which the index is incremented by
  2343.                    n1 each time the loop executes.
  2344.  
  2345.                    The branch back to DO occurs as long as the index remains
  2346.                    less than the limit if n1 > 0, or for as long as it is
  2347.                    greater than the limit if n1 < 0.
  2348.  
  2349.                    Note than n1 can be positive or negative for this word.
  2350.  
  2351.      /LOOP         ( n1 _ _ _ )
  2352.  
  2353.                    Used in colon definitions in the form:
  2354.  
  2355.                                  DO - - - - - n1 /LOOP
  2356.  
  2357.                    to implement a loop in which the index is incremented by
  2358.                    n1 each time the loop executes.
  2359.  
  2360.                    The branch back to DO occurs as long as the index remains
  2361.                    less than the limit.
  2362.  
  2363.                    In this case n1 must always be positive (unsigned) and
  2364.                    the loop index can exceed 32767.
  2365.  
  2366. For example:
  2367.  
  2368. :  PLUSLOOP  10  0  DO  I  .  2 +LOOP  ;
  2369.  
  2370. PLUSLOOP
  2371.  
  2372. will give us:
  2373.  
  2374. 0 2 4 6 8
  2375.  
  2376. Now look at these more interesting examples:
  2377.  
  2378.  
  2379. :  NEGLOOP1  10  0  DO  I  .  -2 +LOOP  ;
  2380.  
  2381. NEGLOOP1
  2382.  
  2383. will give us:
  2384.  
  2385. 0
  2386.  
  2387. :  NEGLOOP2  0 10 DO  I  .  -2 +LOOP  ;
  2388.  
  2389. NEGLOOP2
  2390.  
  2391. will give us:
  2392.  
  2393. 10 8 6 4 2 0
  2394.  
  2395. :  NEGLOOP3  -10  0  DO  I  .  -2 +LOOP  ;
  2396.  
  2397. NEGLOOP3
  2398.  
  2399. will give us:
  2400.  
  2401. 0 -2 -4 -6 -8 -10
  2402.  
  2403. Look at these examples and try to follow the way the loop index and limit
  2404. are being used to control the loop.
  2405.  
  2406. Here is another interesting example:
  2407.  
  2408. :  DOUBLE-LOOP  CR  200 1  DO  I  .  I  +LOOP  ;
  2409.  
  2410. Here the index itself is used as the increment so that starting with
  2411. one the index doubles each time:
  2412.  
  2413. 1  2  4  8  16  32  64  128  256  etc.
  2414.  
  2415. Note that in this example we did not set the loop index to start at "0".
  2416.  
  2417. Can you see why?
  2418.  
  2419. Yes, if we had done so the argument for +LOOP would have been "0", and in
  2420. this case we would have created an infinite loop because the loop index
  2421. would never change.
  2422.  
  2423.  
  2424. -----------------
  2425. Conditional Loops
  2426. -----------------
  2427.  
  2428. Conditional loops repeat until a certain condition is met, and are created,
  2429. at their simplest, by using the "BEGIN...UNTIL" construct.
  2430.  
  2431. We say "at their simplest" because there are a few more complex variants
  2432. such as BEGIN...WHILE...REPEAT.
  2433.  
  2434. Here are a few word definitions:
  2435.  
  2436.      BEGIN         ( _ _ _ )
  2437.  
  2438.                    Used in colon definitions in the forms :
  2439.  
  2440.                    * BEGIN - - - - - UNTIL
  2441.  
  2442.                      Repeats if top stack value is "0" at UNTIL
  2443.  
  2444.  
  2445.                    * BEGIN - - - - - AGAIN
  2446.  
  2447.  
  2448.                      Repeats always
  2449.  
  2450.                    * BEGIN - - - - - WHILE - - - - - REPEAT
  2451.  
  2452.                      If WHILE finds a 0, it diverts execution to beyond
  2453.                      REPEAT, leaving the conditional structure.
  2454.  
  2455.                      If flag for WHILE is "true", execution is allowed to
  2456.                      continue through to REPEAT and then back to BEGIN.
  2457.  
  2458.                    BEGIN marks the start of a repeating section of code and
  2459.                    a return point for UNTIL, AGAIN, and REPEAT.
  2460.  
  2461.  
  2462.      REPEAT        ( _ _ _ )
  2463.  
  2464.                    Used in colon definitions to force execution to return to
  2465.                    the point just after the word BEGIN.
  2466.  
  2467.  
  2468.      UNTIL         ( flag _ _ _ )
  2469.  
  2470.                    Used in colon definitions to control a conditional branch
  2471.                    back to BEGIN.
  2472.  
  2473.                    If flag is false execution reverts to BEGIN, but if true
  2474.                    execution continues ahead.
  2475.  
  2476.  
  2477.      WHILE         ( flag _ _ _ )
  2478.  
  2479.                    Used in colon definitions to implement
  2480.  
  2481.                    BEGIN - - - WHILE - - - REPEAT
  2482.  
  2483.                    conditional structures.
  2484.  
  2485.                    If flag is "false", WHILE diverts execution to beyond
  2486.                    REPEAT, leaving the conditional structure.
  2487.  
  2488.                    If flag is "true", execution is allowed to continue
  2489.                    through to REPEAT and then back to BEGIN.
  2490.  
  2491.  
  2492. Looking at the simple BEGIN...UNTIL loop, we can see that it is a very
  2493. simple conditional structure.
  2494.  
  2495. Here is an example:
  2496.  
  2497. :  WAIT-KEY  BEGIN ?TERMINAL UNTIL  ;
  2498.  
  2499. WAIT-KEY
  2500.  
  2501. This is so simple that it hardly needs explanation: the loop simply cycles
  2502. until the value left on the stack by ?TERMINAL is non-zero, then execution
  2503. continues from after UNTIL.
  2504.  
  2505. Although BEGIN...UNTIL loops are very simple, they are very powerful and
  2506. useful.  Sometimes, however, you need a slightly more powerful version of
  2507. the conditional loop, and this is provided by the BEGIN...WHILE...REPEAT
  2508. loop construct.
  2509.  
  2510. In this variant of the conditional loop, the "clever bit" is performed by
  2511. the word WHILE, which acts according to a flag which it receives on the
  2512. stack.  If this flag is "false", WHILE diverts execution to beyond REPEAT,
  2513. leaving the conditional structure.  If the flag is "true", execution is
  2514. allowed to continue through to REPEAT and then back to BEGIN.
  2515.  
  2516. Here is an example:
  2517.  
  2518.   : WAIT-REPEAT
  2519.  
  2520.   SCRCLR
  2521.   20 8 CURPUT
  2522.   ." I'm waiting for a key!"
  2523.  
  2524.   BEGIN
  2525.     BELL
  2526.     ?TERMINAL 0=
  2527.   WHILE
  2528.     ." ."
  2529.     5 DELAY
  2530.   REPEAT
  2531.  
  2532.   SCRCLR
  2533.  
  2534.   20 8 CURPUT
  2535.   ." Thank You!"
  2536.  
  2537.   20 15 CURPUT
  2538.   ." Please press <Space> to continue...."
  2539.  
  2540.   WAITSPACE
  2541.   ;
  2542.  
  2543.   WAIT-REPEAT
  2544.  
  2545. --------------
  2546. Infinite Loops
  2547. --------------
  2548.  
  2549. The final form of loop construct is the infinite loop, and this can be set
  2550. up using BEGIN AGAIN.
  2551.  
  2552. As you might expect, this type of loop is fairly permanent, and will simply
  2553. cycle around for ever.....
  2554.  
  2555. Actually you can exit from an infinite loop by using a word such as ABORT,
  2556. or by using SYS@ and SYS!.  However, these techniques do require a little
  2557. experience, and are only mentioned here for the sake of completeness.
  2558.  
  2559. See the Dictionary documentation for more details.
  2560.  
  2561. *************************************************************************
  2562. End
  2563. *************************************************************************
  2564.